package cn.jzk.mySpringSecurity_noSeparation.Config;

import cn.jzk.mySpringSecurity_noSeparation.SecurityHandler.*;
import org.springframework.context.annotation.*;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

/**
 * 过滤链配置类
 * @author jiangzk
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class WebSecurityConfig {

    /**
     * 过滤链
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorize -> authorize
                    // 放行Swagger相关的路径
                    .requestMatchers("/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**", "/webjars/**").permitAll()
                    // 除 Controller 中自定义权限接口以外的所有请求都需要认证
                    .anyRequest()
                    // 已认证的请求会被自动授权
                    .authenticated()
        );
        http.formLogin(form -> {form
                    // 规定当前登录接口，设置为无需登录认证即可访问
                    .loginPage("/userLogin").permitAll()
                    // 设置认证成功后的响应类
                    .successHandler(new MyAuthenticationSuccessHandler())
                    // 设置认证失败后的响应类
                    .failureHandler(new MyAuthenticationFailureHandler());
        });
        http.logout(logout -> {logout
                    // 设置用户注销后的响应类
                    .logoutSuccessHandler(new MyLogoutSuccessHandler());
        });
        http.exceptionHandling(exception -> {exception
                    // 设置请求未认证接口的响应类
                    .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                    // 设置未授权访问接口的响应类
                    .accessDeniedHandler(new MyAccessDeniedHandler());
        });
        http.sessionManagement(session -> {session
                    // 设置在同一个账号下，最多同时可以在几个客户端进行登录；若超出限制，则进行会话并发响应
                    .maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy());
        });

        // 允许跨域
        http.cors(Customizer.withDefaults());

        // 禁用 basic
        http.httpBasic(AbstractHttpConfigurer::disable);

        // 关闭csrf攻击防御
        http.csrf(AbstractHttpConfigurer::disable);
        return http.build();
    }

    /**
     * 密码加密算法
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}